package org.bob.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggest;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggester;
import co.elastic.clients.elasticsearch.core.search.FieldSuggester;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import lombok.extern.slf4j.Slf4j;
import org.bob.common.constant.SuggestTypeEnum;
import org.bob.service.SuggestService;
import org.bob.web.model.SuggestReq;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 搜索建议服务实现类
 * 搜索维度：中文、中文全拼、中文拼音首字母，可以通过Type字段选择支持单一搜索模式，具体见SuggestTypeEnum类定义
 */
@Slf4j
@Service
public class SuggestServiceImpl implements SuggestService {

    /**
     * 固定字段名称
     */
    private final static String INPUT = "input";

    private ElasticsearchClient elasticsearchClient;

    public SuggestServiceImpl(ElasticsearchClient elasticsearchClient) {
        this.elasticsearchClient = elasticsearchClient;
    }

    @Override
    public List<String> search(SuggestReq req) {
        SearchRequest searchRequest = SearchRequest.of(s->s.index(req.getIndex()).suggest(fn->fn.text(req.getPrefix()).suggesters(buildSuggesters(req))));
        try {
            return parseResponse(elasticsearchClient.search(searchRequest,Object.class));
        } catch (Exception e) {
            log.info("",e.getMessage());
            return Collections.emptyList();
        }

    }

    /**
     * 字段建议构建器
     * @param req
     * @return
     */
    private static Map<String, FieldSuggester> buildSuggesters(SuggestReq req){
       return SuggestTypeEnum.valuesOfCode(req.getType()).stream()
               .collect(Collectors.toMap(SuggestTypeEnum::getName,suggestTypeEnum -> FieldSuggester.of(fsf->fsf.completion(new CompletionSuggester.Builder().field(suggestTypeEnum.getName()).size(req.getSize()).build()))));
    }

    /**
     * 解析响应获取搜索子结果对象集
     * @param response
     * @return
     */
    private static List<String> parseResponse(SearchResponse<Object> response){
        return response.suggest().values().stream().flatMap(List::stream).map(Suggestion::completion).map(CompletionSuggest::options).
                flatMap(List::stream).map(CompletionSuggestOption::source).map(sourceMapper).collect(Collectors.toList());
    }

    /**
     * 解析source获取中文搜索建议
     */
    private static Function<Object,String> sourceMapper = source -> {
        Map<String,Object> sm = (Map<String,Object>)source;
        Map<String,Object> chinese = (Map<String,Object>)sm.get(SuggestTypeEnum.CHINESE.getName());
        return (String)chinese.get(INPUT);
    };
}
